using Fusion.Utilities.Generics;
using Fusion.Utilities.Singleton;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

namespace Fusion.Async.Coroutines
{
    public class CoroutineData
    {
        private Coroutine coroutine;
        private IEnumerator enumerator;
        private IEnumerator wrapedEnumerator;

        private bool persistent = false;
        public CoroutineData(Coroutine coroutine, IEnumerator enumerator, IEnumerator wrapedEnumerator, bool persistent)
        {
            this.coroutine = coroutine;
            this.enumerator = enumerator;
            this.wrapedEnumerator = wrapedEnumerator;
            this.persistent = persistent;
        }

        public Coroutine Coroutine { get => coroutine; }
        public IEnumerator Enumerator { get => enumerator; }
        public IEnumerator WrapedEnumerator { get => wrapedEnumerator; }
        public bool Persistent { get => persistent; }
    }

    [DisallowMultipleComponent]
    public class CoroutineManager : SingletonBehaviour<CoroutineManager>
    {
        private OrderDictionary<IEnumerator, CoroutineData> coroutineDatas = new OrderDictionary<IEnumerator, CoroutineData>();

        private IEnumerator WrapCoroutine(IEnumerator enumerator)
        {
            yield return enumerator;
            coroutineDatas.Remove(enumerator);
        }

        public CoroutineData InvokeCoroutine(IEnumerator enumerator, bool persistent = false)
        {
            IEnumerator wrapedEnumerator = WrapCoroutine(enumerator);
            Coroutine coroutine = StartCoroutine(wrapedEnumerator);
            CoroutineData coroutineData = new CoroutineData(coroutine, enumerator, wrapedEnumerator, persistent);
            coroutineDatas[enumerator] = coroutineData;
            return coroutineData;
        }

        public bool CheckAllCoroutineFinished(bool includePersistent = false)
        {
            if (includePersistent)
            {
                int count = coroutineDatas.Count;
                for (int index = 0; index < count; index++)
                {
                    if (!coroutineDatas.Get(index).Persistent)
                    {
                        return false;
                    }
                }
                return true;
            }
            else
            {
                return coroutineDatas.Count <= 0;
            }
        }

        public void StopCoroutine(CoroutineData coroutineData)
        {
            StopCoroutine(coroutineData.Coroutine);
            coroutineDatas.Remove(coroutineData.Enumerator);
        }
    }
}

